"""
插件管理器 - 优化版，支持递归遍历所有子目录
"""
import importlib
import os
import sys
from typing import Dict, Type, Any
import logging

from numpy.f2py.auxfuncs import throw_error

# 添加项目根目录到Python路径
current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.join(current_dir, '..', '..')
sys.path.insert(0, project_root)

from plugins.base_plugin import BasePlugin
from core.logger import get_logger

# 获取日志记录器
logger = get_logger(__name__)


class PluginManager:
    """插件管理器"""

    def __init__(self, plugin_dirs: list = None):
        self.plugin_dirs = plugin_dirs or ["src/plugins"]
        self.registered_plugins: Dict[str, Type[BasePlugin]] = {}
        self._discovered_modules = set()  # 记录已发现的模块，避免重复
        self._discover_plugins()

    def _discover_plugins(self):
        """自动发现插件"""
        try:
            self._discover_plugins_auto()
        except ImportError as e:
            logger.error(f"Failed to discover plugins: {e}")
            raise e

    def _discover_plugins_auto(self):
        """递归遍历插件目录，自动发现所有插件"""
        for plugin_dir in self.plugin_dirs:
            # 构建完整的插件目录路径
            if not os.path.isabs(plugin_dir):
                full_plugin_dir = os.path.join(project_root, plugin_dir.replace('/', os.sep).replace('\\', os.sep))
            else:
                full_plugin_dir = plugin_dir

            logger.info(f"Looking for plugins in: {full_plugin_dir}")

            if not os.path.exists(full_plugin_dir):
                logger.warning(f"Plugin directory does not exist: {full_plugin_dir}")
                continue

            # 递归遍历目录下的所有Python文件
            self._scan_directory_recursively(full_plugin_dir, plugin_dir)

    def _scan_directory_recursively(self, full_dir_path: str, relative_dir: str):
        """递归扫描目录下的所有Python文件"""
        try:
            # 获取目录下的所有项目
            items = os.listdir(full_dir_path)

            for item in items:
                item_path = os.path.join(full_dir_path, item)

                # 如果是目录且不是特殊目录，递归扫描
                if os.path.isdir(item_path) and not item.startswith('__') and not item.startswith('.'):
                    logger.info(f"Scanning subdirectory: {item_path}")
                    new_relative_dir = os.path.join(relative_dir, item)
                    self._scan_directory_recursively(item_path, new_relative_dir)

                # 如果是Python文件，尝试导入
                elif item.endswith('.py') and not item.startswith('__'):
                    module_name = item[:-3]
                    self._import_plugin_module(relative_dir, module_name, item_path)

        except PermissionError as e:
            logger.error(f"Permission denied accessing directory {full_dir_path}: {e}")
        except Exception as e:
            logger.error(f"Error scanning directory {full_dir_path}: {e}")
            raise e



    def _import_plugin_module(self, relative_dir: str, module_name: str, file_path: str):
        """导入插件模块"""
        try:
            # 构建模块导入路径
            normalized_dir = relative_dir.replace('/', '.').replace('\\', '.')

            # 根据相对目录结构构建完整的模块名
            if relative_dir.startswith("src/"):
                full_module_name = f"{normalized_dir}.{module_name}"
            else:
                full_module_name = f"src.{normalized_dir}.{module_name}"

            # 检查模块是否已导入
            if full_module_name in self._discovered_modules:
                logger.error(f"Module {full_module_name} already discovered")
                raise ValueError(f"Module {full_module_name} already discovered")

            # 添加到已发现集合
            self._discovered_modules.add(full_module_name)

            logger.info(f"Trying to import module: {full_module_name}")

            # 获取文件所在目录
            module_dir = os.path.dirname(file_path)

            # 确保模块所在目录在Python路径中
            if module_dir not in sys.path:
                sys.path.insert(0, module_dir)

            # 使用importlib导入模块
            spec = importlib.util.spec_from_file_location(full_module_name, file_path)
            if spec and spec.loader:
                module = importlib.util.module_from_spec(spec)
                spec.loader.exec_module(module)
                self._register_plugins_from_module(module)
                logger.info(f"Successfully imported module: {full_module_name}")
            else:
                logger.error(f"Failed to create module spec for {full_module_name}")

        except ImportError as e:
            logger.error(f"Failed to import module {module_name} from {relative_dir}: {e}")
            raise e
        except Exception as e:
            logger.error(f"Unexpected error importing module {module_name}: {e}")
            logger.error(f"File path: {file_path}")
            logger.error(f"Module name: {module_name}")
            logger.error(f"Relative dir: {relative_dir}")
            raise e

    def _register_plugins_from_module(self, module):
        """从模块中注册插件"""
        for attr_name in dir(module):
            attr = getattr(module, attr_name)
            if (isinstance(attr, type) and
                    issubclass(attr, BasePlugin) and
                    attr != BasePlugin):
                logger.info(f"Registering plugin: {attr_name}")
                # 检查插件是否已注册
                if attr_name in self.registered_plugins:
                    logger.error(f"Plugin {attr_name} already registered")
                    raise ImportError(f"Plugin {attr_name} already registered")

                self.registered_plugins[attr_name] = attr

    def create_plugin(self, plugin_type: str, plugin_id: str, config: Dict[str, Any] = None) -> BasePlugin:
        """创建插件实例"""
        logger.debug(f"Attempting to create plugin of type: {plugin_type}")
        logger.debug(f"Registered plugins: {list(self.registered_plugins.keys())}")

        if plugin_type not in self.registered_plugins:
            available_plugins = list(self.registered_plugins.keys())
            raise ValueError(f"Plugin type {plugin_type} not registered. Available plugins: {available_plugins}")

        plugin_class = self.registered_plugins[plugin_type]
        return plugin_class(plugin_id, config)

    def get_registered_plugins(self) -> Dict[str, Type[BasePlugin]]:
        """获取已注册的插件"""
        return self.registered_plugins.copy()